{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "69032b4b-b031-4020-beb0-e8dfd22b660e",
   "metadata": {},
   "source": [
    "# LangChain 实战：房产销售聊天机器人"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f3e2d5a-c2ff-4faf-b153-d1751c25fae0",
   "metadata": {},
   "source": [
    "## 使用 GPT-4 构造销售话术数据\n",
    "\n",
    "ChatGPT 分享链接：https://chat.openai.com/share/f3e4b9b0-95fb-4c6a-a3c7-f901dd194c91\n",
    "\n",
    "\n",
    "使用 ChatGPT 构造销售数据的 Prompt 示例：\n",
    "\n",
    "```\n",
    "你是中国顶级的房地产销售，现在培训职场新人，请给出100条实用的销售话术。\n",
    "\n",
    "每条销售话术以如下格式给出：\n",
    "[客户问题]\n",
    "[销售回答]\n",
    "\n",
    "```\n",
    "\n",
    "GPT-4 回复结果：\n",
    "\n",
    "```\n",
    "在房地产销售行业中，精心准备的销售话术可以极大地提高成交率。以下是一些适用于中国房地产销售的实用话术：\n",
    "\n",
    "1.  \n",
    "[客户问题] 这个小区交通便利吗？\n",
    "[销售回答] 当然了，这个小区距离地铁站只有几分钟的步行距离，而且附近有多条公交线路，非常方便。\n",
    "\n",
    "2.  \n",
    "[客户问题] 我担心楼下太吵。\n",
    "[销售回答] 这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。\n",
    "\n",
    "3.  \n",
    "[客户问题] 我看房价还在涨，这个投资回报怎么样？\n",
    "[销售回答] 这个区域未来有大量的商业和基础设施建设，所以从长期来看，投资回报非常有保证。\n",
    "\n",
    "4.  \n",
    "[客户问题] 有没有学校？\n",
    "[销售回答] 附近有多所优质的学校，非常适合有孩子的家庭。\n",
    "\n",
    "5.  \n",
    "[客户问题] 物业管理怎么样？\n",
    "[销售回答] 我们的物业管理得到了业主一致好评，服务非常到位。\n",
    "\n",
    "6.  \n",
    "[客户问题] 我想要南向的房子。\n",
    "[销售回答] 很好，我们确实有一些朝南的单位，它们的采光特别好。\n",
    "\n",
    "7.  \n",
    "[客户问题] 这个小区安全吗？\n",
    "[销售回答] 当然，我们24小时安保巡逻，还有先进的监控系统。\n",
    "\n",
    "8.  \n",
    "[客户问题] 预计什么时候交房？\n",
    "[销售回答] 根据目前的进度，我们预计将在明年底交房。\n",
    "\n",
    "9.  \n",
    "[客户问题] 我不想要一楼的房子。\n",
    "[销售回答] 我理解您的顾虑，我们还有多个楼层的房源可以选择。\n",
    "\n",
    "10.  \n",
    "[客户问题] 有优惠吗？\n",
    "[销售回答] 当然，如果您现在下订，我们可以给您一些优惠。\n",
    "```\n",
    "\n",
    "\n",
    "## 使用 Document Transformers 模块来处理原始数据\n",
    "\n",
    "\n",
    "将 ChatGPT 生成的结果保存到 [real_estate_sales_data.txt](real_estate_sales_data.txt) 文件中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "efcee928-b9f4-4e4a-b9fb-f6cbee21b642",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"real_estate_sales_data.txt\") as f:\n",
    "    real_estate_sales = f.read()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a9119556-d2e3-4edf-be16-15837da156f1",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "source": [
    "### 使用 CharacterTextSplitter 来进行文本分割\n",
    "\n",
    "- 基于单字符来进行文本分割（separator）\n",
    "- 基于字符数来决定文本块长度（chunk_size）\n",
    "\n",
    "参考示例：\n",
    "\n",
    "```python\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "text_splitter = CharacterTextSplitter(        \n",
    "    separator = \"\\n\\n\",\n",
    "    chunk_size = 1000,\n",
    "    chunk_overlap  = 200,\n",
    "    length_function = len,\n",
    "    is_separator_regex = False,\n",
    ")\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "dbe535b8-2bd8-4c31-91d7-eba8aa61b3ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.text_splitter import CharacterTextSplitter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a4f30d9b-9fc6-4860-a497-0aa8220b9284",
   "metadata": {},
   "outputs": [],
   "source": [
    "text_splitter = CharacterTextSplitter(        \n",
    "    separator = r'\\d+\\.',\n",
    "    chunk_size = 100,\n",
    "    chunk_overlap  = 0,\n",
    "    length_function = len,\n",
    "    is_separator_regex = True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "530f3172-17a5-4924-ad17-284fbca422ae",
   "metadata": {},
   "outputs": [],
   "source": [
    "docs = text_splitter.create_documents([real_estate_sales])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "3956ec36-706e-4f43-88fc-d704f2984290",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Document(page_content='[客户问题] 这个小区交通便利吗？\\n[销售回答] 当然了，这个小区距离地铁站只有几分钟的步行距离，而且附近有多条公交线路，非常方便。')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "73b2d47a-27ae-4cd4-a72a-3809b4c22bff",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "70"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(docs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4617858-ad9c-42eb-a4c3-6bfb7108cdd2",
   "metadata": {},
   "source": [
    "### 使用 Faiss 作为向量数据库，持久化存储房产销售 问答对（QA-Pair）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "508c2ab2-e187-424f-a43c-ca3d3b1a0550",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.embeddings.openai import OpenAIEmbeddings\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "from langchain.vectorstores import FAISS\n",
    "\n",
    "db = FAISS.from_documents(docs, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "250e0873-95e2-4372-98a5-68c0feb304bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "query = \"小区吵不吵\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0d18fcc6-c2be-434b-b8de-9648ac6f83f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "answer_list = db.similarity_search(query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e689667e-7a45-40d6-9eae-4e52cbc7daab",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[客户问题] 我担心楼下太吵。\n",
      "[销售回答] 这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。\n",
      "\n",
      "[客户问题] 我担心楼下的商业活动会很吵。\n",
      "[销售回答] 我们在规划时就已经考虑到这一点，商业区和居住区有一定的距离和隔音设计。\n",
      "\n",
      "[客户问题] 我喜欢安静，这里噪音大吗？\n",
      "[销售回答] 我们特意进行了隔音设计，并且小区内部也有绿化带，整体非常安静。\n",
      "\n",
      "[客户问题] 我担心小区会很拥挤。\n",
      "[销售回答] 这个小区总体规划非常合理，保证了每个单元之间有足够的空间。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for ans in answer_list:\n",
    "    print(ans.page_content + \"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "a6cc47bf-1566-472f-84d2-a46bd634907c",
   "metadata": {},
   "outputs": [],
   "source": [
    "db.save_local(\"real_estates_sale\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d5323e5-03fa-4c1c-b896-3ccc28af1857",
   "metadata": {},
   "source": [
    "### 使用 retriever 从向量数据库中获取结果\n",
    "\n",
    "#### 使用参数 `k` 指定返回结果数量\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "17f051c9-8676-48d1-a9a4-e69b52630faf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实例化一个 TopK Retriever\n",
    "topK_retriever = db.as_retriever(search_kwargs={\"k\": 3})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "e33024db-ca7b-4d68-9b0e-c31c15ded57d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "VectorStoreRetriever(tags=['FAISS'], vectorstore=<langchain.vectorstores.faiss.FAISS object at 0x7f4f83a18ee0>, search_kwargs={'k': 3})"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "topK_retriever"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "7efb1414-859f-4818-bacd-e1e2edf34b95",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[客户问题] 我担心楼下太吵。\n",
      "[销售回答] 这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。\n",
      "\n",
      "[客户问题] 我担心楼下的商业活动会很吵。\n",
      "[销售回答] 我们在规划时就已经考虑到这一点，商业区和居住区有一定的距离和隔音设计。\n",
      "\n",
      "[客户问题] 我喜欢安静，这里噪音大吗？\n",
      "[销售回答] 我们特意进行了隔音设计，并且小区内部也有绿化带，整体非常安静。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "docs = topK_retriever.get_relevant_documents(query)\n",
    "for doc in docs:\n",
    "    print(doc.page_content + \"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "a3c4b62d-6f8f-461b-a4fb-41c8a404b831",
   "metadata": {},
   "outputs": [],
   "source": [
    "docs = topK_retriever.get_relevant_documents(\"你们有没有1000万的豪宅啊？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "04cca3d7-23d9-491f-8350-faeb19861dec",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[客户问题] 你们会提供家具吗？\n",
      "[销售回答] 我们的精装房会提供基础家具和家电，让您拎包入住。\n",
      "\n",
      "[客户问题] 我不想要一楼的房子。\n",
      "[销售回答] 我理解您的顾虑，我们还有多个楼层的房源可以选择。\n",
      "\n",
      "[客户问题] 都有哪些户型？\n",
      "[销售回答] 我们有从一室到四室不等的多种户型，定能满足您不同的居住需求。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for doc in docs:\n",
    "    print(doc.page_content + \"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b335c9e5-bc01-4a47-916c-03bec0e7a839",
   "metadata": {},
   "source": [
    "#### 使用 similarity_score_threshold 设置阈值，提升结果的相关性质量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "b1298956-6cf3-4a68-a3c2-a3149f64f156",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实例化一个 similarity_score_threshold Retriever\n",
    "retriever = db.as_retriever(\n",
    "    search_type=\"similarity_score_threshold\",\n",
    "    search_kwargs={\"score_threshold\": 0.8}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "d61167de-72ed-4618-a2e1-5df04784a3bc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[客户问题] 我担心楼下太吵。\n",
      "[销售回答] 这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "docs = retriever.get_relevant_documents(query)\n",
    "for doc in docs:\n",
    "    print(doc.page_content + \"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "548d1b52-6fa2-46d6-9218-908db572f380",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "c31344ce-f952-4604-b700-fdbb34da1e28",
   "metadata": {},
   "source": [
    "### 提取向量数据库中的`销售回答`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "25768463-da65-4762-978d-51c0c3a9c24b",
   "metadata": {},
   "outputs": [],
   "source": [
    "docs = retriever.get_relevant_documents(query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "4838d3da-dca3-4c31-80da-cec75760a833",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'[客户问题] 我担心楼下太吵。\\n[销售回答] 这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。'"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[0].page_content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "1ba30232-f468-4102-b70c-02c8b74da43d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['[客户问题] 我担心楼下太吵。\\n', '这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。']"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[0].page_content.split(\"[销售回答] \")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "bda8eb0c-eb1f-47b2-91ab-4c94ff71c3db",
   "metadata": {},
   "outputs": [],
   "source": [
    "ans = docs[0].page_content.split(\"[销售回答] \")[-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "917a3b6c-3149-42e2-b7b6-abebd94b7f72",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ans"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b36b61a5-156d-4546-bbd1-8a983e94676b",
   "metadata": {},
   "source": [
    "#### 尝试各种问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "c311a656-e571-45d6-8690-88e4be2c2a65",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "\n",
    "def sales(query: str, score_threshold: float=0.8) -> List[str]:\n",
    "    retriever = db.as_retriever(search_type=\"similarity_score_threshold\", search_kwargs={\"score_threshold\": score_threshold})    \n",
    "    docs = retriever.get_relevant_documents(query)\n",
    "    ans_list = [doc.page_content.split(\"[销售回答] \")[-1] for doc in docs]\n",
    "\n",
    "    return ans_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "2f4c6c08-b97c-4727-9aa1-a474d85a11e4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/miniconda3/envs/langchain/lib/python3.10/site-packages/langchain/schema/vectorstore.py:287: UserWarning: No relevant docs were retrieved using the relevance score threshold 0.8\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "query = \"我想离医院近点\"\n",
    "\n",
    "print(sales(query))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "11e3d8b6-839f-4b2f-b519-841e0271f95b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['有的，距离我们小区不远就有几家大型综合医院。', '是的，附近有多家大型医院，医疗资源非常丰富。']\n"
     ]
    }
   ],
   "source": [
    "print(sales(query, 0.75))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "fc5b030a-ae6f-4d42-9577-1420c78aecb1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:0.8 ans: []\n",
      "\n",
      "score:0.75 ans: []\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/miniconda3/envs/langchain/lib/python3.10/site-packages/langchain/schema/vectorstore.py:287: UserWarning: No relevant docs were retrieved using the relevance score threshold 0.75\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:0.5 ans: ['我们有不同户型和付款方案，一定有适合您预算的。', '我们的房子位于黄金地段，升值潜力很大，转卖起来不会有问题。', '定金金额取决于您选择的房型和付款方式，我们可以详细为您解释。', '这个区域正在快速发展，未来的升值潜力非常大。']\n",
      "\n"
     ]
    }
   ],
   "source": [
    "query = \"价格200万以内\"\n",
    "\n",
    "print(f\"score:0.8 ans: {sales(query)}\\n\")\n",
    "print(f\"score:0.75 ans: {sales(query, 0.75)}\\n\")\n",
    "print(f\"score:0.5 ans: {sales(query, 0.5)}\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e26e6d7-259b-4ecf-9c72-027befba4e3b",
   "metadata": {},
   "source": [
    "#### 当向量数据库中没有合适答案时，使用大语言模型能力"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "9142feb4-980a-4142-b367-1401021dceef",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(model_name=\"gpt-4-1106-preview\", temperature=0.5)\n",
    "qa_chain = RetrievalQA.from_chain_type(llm,\n",
    "                                       retriever=db.as_retriever(search_type=\"similarity_score_threshold\",\n",
    "                                                                 search_kwargs={\"score_threshold\": 0.8}))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "d281b560-54bb-4a25-a1dc-b23874361654",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'query': '你们小区有200万的房子吗？',\n",
       " 'result': '对不起，我无法回答这个问题，因为我是一个人工智能，没有实时的房地产信息。建议你直接联系房地产经纪人或者查阅相关房地产网站获取信息。'}"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qa_chain({\"query\": \"你们小区有200万的房子吗？\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "c6a30dcc-fa6b-4282-935c-b07902746e19",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'query': '小区吵不吵',\n",
       " 'result': '这个小区特别注重居住体验，有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。所以，小区应该不会太吵。'}"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qa_chain({\"query\": \"小区吵不吵\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "9da44bd6-02ef-4fb6-8e9e-7c99aeba483a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['这个小区特别注重居住体验，我们有良好的隔音设计，并且小区内部规划了绿化区域，可以有效降低噪音。']\n"
     ]
    }
   ],
   "source": [
    "print(sales(\"小区吵不吵\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9764bb10-44ed-47c9-a351-a68f4f7d4f44",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "0a0647e8-5b41-4c93-87c2-3240ec558717",
   "metadata": {},
   "source": [
    "## 加载 FAISS 向量数据库已有结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "913edd04-37ea-4c3f-9346-086aeb0ab447",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain.vectorstores import FAISS\n",
    "\n",
    "db = FAISS.load_local(\"real_estates_sale\", OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "77d8eee4-6383-4b4a-9737-95ea9fc53b87",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(model_name=\"gpt-4\", temperature=0.5)\n",
    "qa_chain = RetrievalQA.from_chain_type(llm,\n",
    "                                       retriever=db.as_retriever(search_type=\"similarity_score_threshold\",\n",
    "                                                                 search_kwargs={\"score_threshold\": 0.8}))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "5dfac197-cadb-47d7-8cbe-1b07a83fc8e1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'query': '我想买别墅，你们有么',\n",
       " 'result': '对不起，我无法提供这样的服务。我是一个人工智能，我可以帮助回答问题，但我不能出售商品或房产。'}"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qa_chain({\"query\": \"我想买别墅，你们有么\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "fc393afc-06d3-4483-bd24-efe000ef5f2a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 输出内部 Chain 的日志\n",
    "qa_chain.combine_documents_chain.verbose = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "013c313a-5e7c-48d1-8ed4-eee96e50a99c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new StuffDocumentsChain chain...\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'query': '我想买别墅，你们有么', 'result': '对不起，我不能帮助你购买别墅，因为我是一个人工智能，没有提供房地产服务的功能。'}"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qa_chain({\"query\": \"我想买别墅，你们有么\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "e5fb0943-ffe9-4270-8dbe-f5f5314e6042",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 返回向量数据库的检索结果\n",
    "qa_chain.return_source_documents = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "fbc1741e-d34f-4df5-874b-02b78e8cd67a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new StuffDocumentsChain chain...\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "result = qa_chain({\"query\": \"我想买别墅，你们有么\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "fac8309c-033c-4144-ada0-08e74fa9bf2d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'query': '我想买别墅，你们有么',\n",
       " 'result': '对不起，我不能帮你购买别墅。我是一个AI助手，我主要用来提供信息和回答问题。',\n",
       " 'source_documents': []}"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37de84df-999f-4469-9bbe-de9c95c6f6b3",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
